// Copyright (c) 1996-2002 John Lyon-Smith. All rights reserved.

#pragma once

#include <wxtl\Base.h>
#include <wxtl\Path.h>

namespace wxtl
{
	enum ArgType
	{
		argBool,
		argString,
		argNumeric,
	};


	struct Argument
	{
		int id;
		const TCHAR *name;
		ArgType type;
		const TCHAR* desc;
	};

	class ParseArgs
	{
	public:
		ParseArgs(int numArgs, TCHAR** ppArgs, Argument* pArgs)
		{
			m_numArgs = numArgs;
			m_ppArgs = ppArgs;
			m_option = NULL;
			m_pArgs = pArgs;
			m_target = -1;
		}

		bool getNext(int& id)
		{
			if (m_numArgs == 1)
			{
				id = 0;
				return false;
			}

			--m_numArgs;
			++m_ppArgs;
				
			if (**m_ppArgs == '/' || **m_ppArgs == '-') 
			{
				id = parseSwitch(*m_ppArgs + 1);
			}
			else
			{
				m_option = *m_ppArgs;
				id = m_target--;
			}

			return true;
		}

		const TCHAR *getOptString()
		{ 
			return m_option; 
		}
		int getOptNumeric()
		{ 
			return _ttoi(m_option); 
		}

		static void formatUsage(tstring& s, Argument* pArgs, size_t nNumFiles = 1)
		{
			const size_t lineLen = 79;
					
			s.erase();

			size_t maxArg = 0;
			tstring sT(getPathParts(getModulePath().c_str(), pathFile));

			s += _T("Usage: "); 
			s += sT;
			s += _T(" <options>");
			if (nNumFiles == 1)
				s += _T(" <filespec>");
			else if (nNumFiles > 1)
				s += _T(" <filespec> [<filespec>]");
			size_t i = 0;
			for (; pArgs[i].id > 0 ; i++)
			{
				sT = getArgString(pArgs[i].name, pArgs[i].type);
				size_t n = sT.size();

				if (n > maxArg)
					maxArg = n;
			}

			s += _T("\n\nOptions:\n\n");

			maxArg++; // Spacing

			for (i = 0; pArgs[i].id > 0 ; i++)
			{
				sT = getArgString(pArgs[i].name, pArgs[i].type);

				tstring sQ(pArgs[i].desc);
				size_t n = sQ.length();
				size_t maxDesc = lineLen - maxArg;
				size_t i = 0;
				tstring sP(sT);
				
				sP.append(maxArg - sT.length(), ' ');

				while (n > maxDesc)
				{
					size_t j = maxDesc;

					while (sQ[i + j - 1] != ' ')
						j--;
					
					sP += sQ.substr(i, j) + _T("\n");
					sP.append(maxArg, ' ');
					n -= j;
					i += j;
				}

				sP += sQ.substr(i) + _T("\n");

				s += sP;
			}
		}

	protected:
		static tstring getArgString(tstring name, ArgType type)
		{
			tstring s(name);

			s += type == argNumeric ? _T(":<n>") : 
				type == argString ? _T(":<s>") : _T("");

			return s;
		}

		int parseSwitch(TCHAR* pArg)
		{
			TCHAR* pch = pArg;
			while (*pch != ':' && *pch != 0)
				pch++;
			if (*pch == ':')
				*pch++ = 0;

			m_option = pch;
			int i;

			wxtl::tchar_separator seps(_T("|"));

			for (i = 0; m_pArgs[i].id > 0 ; i++)
			{
				tstring str(m_pArgs[i].name);
				
				wxtl::ttokenizer tok(str, seps);
				
				for (wxtl::ttokenizer::iterator iter = tok.begin(); iter != tok.end(); iter++)
				{
					if (_tcsnicmp(iter->c_str(), pArg, _tcslen(pArg)) == 0)
						return m_pArgs[i].id;
				}
			}

			// Do this to help error messages
			m_option = pArg;
			return 0;	
		}

	// Data
		TCHAR **m_ppArgs;
		int m_numArgs;
		TCHAR *m_option;
		Argument* m_pArgs;
		int m_target;
	};
}

